package fr.afcepf.atod16.groupe1.projet3;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author cedric
 */
public class MyBeanPopulate {

    public static Object populateBean(Object theObject, Map params) {
        Map<String, String[]> parameters = params;
        ArrayList<MethodeInfo> lesMethodes = new ArrayList<MethodeInfo>();

        //Recupere la liste de toute les methodes de la class passé en parametre 'theObject'
        Method[] listMethodes = theObject.getClass().getMethods();

        //Boucle sur la liste des methodes
        //Instanciation d'un objet 'methodeInfo' pour chaque boucle  
        //Recuperation des methodes + les Noms des variables + les parametres d'entrée.
        for (Method method : listMethodes) {


            //Filtre :  on recupere seulement les methode 'setter' (commence par set).
            if (method.getName().startsWith("set")) {
                MethodeInfo methodeInfo = new MethodeInfo();
                //Pour recuperer le nom de la variable , on enleve les 3 premieres lettres 'set'
                //et la 4 eme lettre est passé en minusucule
                String nomVariable = method.getName().replaceFirst("set", "");
                nomVariable = String.valueOf(nomVariable.charAt(0)).toLowerCase() + nomVariable.substring(1);
                methodeInfo.setNomDeVariable(nomVariable);
                methodeInfo.setMethod(method);

                //boucle pour chaque parametre attendu a la methode (normalement un setter aura 1 seul parametre
                // dans la signature.
                Class[] listeParametres = method.getParameterTypes();
                for (Class c : listeParametres) {
                    methodeInfo.addParametre(c);
                }
                lesMethodes.add(methodeInfo);
            }
        }


        //Parcous des methodes du tableau et appel des Setter avec les bons parametres passé en args
        for (MethodeInfo infoMethod : lesMethodes) {
            String[] parametresDeMethode = parameters.get(infoMethod.getNomDeVariable());
            for (Class method : infoMethod.getParametres()) {
                try {
                    //Recuperation du parametre a envoyer au setter
                    Object o = castEtSetDesAttributPasserEnParametre(method.getSimpleName(), parametresDeMethode);
                    //Appel du setter avec le parametre recupéré.
                    if (o != null) {
                        infoMethod.getMethod().invoke(theObject, o);
                    }
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(MyBeanPopulate.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalArgumentException ex) {
                    Logger.getLogger(MyBeanPopulate.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InvocationTargetException ex) {
                    Logger.getLogger(MyBeanPopulate.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return theObject;
    }

    private static Object castEtSetDesAttributPasserEnParametre(String simpleName, String[] parametresDeMethode) {
        //Si la variable n'est pas un tableau static
        if (simpleName.endsWith("[]")) {
            return attributionTypeTableau(simpleName.substring(0, simpleName.length() - 2), parametresDeMethode);
        } //Si la variable est un tableau Static
        else {
            return attributionTypeSimple(simpleName, parametresDeMethode);
        }

    }

    private static Object attributionTypeSimple(String simpleName, String[] parametresDeMethode) {
        if (parametresDeMethode == null) {
            return null;
        }

        if (simpleName.equals("String")) {
            return parametresDeMethode[0];
        } else if (simpleName.equals("int")) {
            return Integer.valueOf(parametresDeMethode[0]);
        } else if (simpleName.equalsIgnoreCase("float")) {
            return Float.valueOf(parametresDeMethode[0]);
        } else if (simpleName.equalsIgnoreCase("boolean")) {
            return Boolean.valueOf(parametresDeMethode[0]);
        } else if (simpleName.equalsIgnoreCase("char")) {
            return parametresDeMethode[0].charAt(0);
        } else if (simpleName.equalsIgnoreCase("byte")) {
            return Byte.valueOf(parametresDeMethode[0]);
        } else if (simpleName.equalsIgnoreCase("short")) {
            return Short.valueOf(parametresDeMethode[0]);
        } else if (simpleName.equalsIgnoreCase("long")) {
            return Long.valueOf(parametresDeMethode[0]);
        } else if (simpleName.equalsIgnoreCase("double")) {
            return Double.valueOf(parametresDeMethode[0]);
        }
        return null;
    }

    private static Object attributionTypeTableau(String simpleName, String[] parametresDeMethode) {
        if (simpleName.equals("String")) {
            return parametresDeMethode;

        } else if (simpleName.equals("int")) {
            Integer[] tab = new Integer[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                tab[i] = Integer.valueOf(parametresDeMethode[i]);
            }
            return tab;

        } else if (simpleName.equalsIgnoreCase("float")) {
            Float[] tab = new Float[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                tab[i] = Float.valueOf(parametresDeMethode[i]);
            }
            return tab;

        } else if (simpleName.equalsIgnoreCase("boolean")) {
            Boolean[] tab = new Boolean[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                tab[i] = Boolean.valueOf(parametresDeMethode[i]);
            }
            return tab;

        } else if (simpleName.equalsIgnoreCase("char")) {
            Character[] tab = new Character[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                if (parametresDeMethode[i].length() > 0) {
                    tab[i] = Character.valueOf(parametresDeMethode[i].charAt(0));
                }
            }
            return tab;

        } else if (simpleName.equalsIgnoreCase("byte")) {
            Byte[] tab = new Byte[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                tab[i] = Byte.valueOf(parametresDeMethode[i]);
            }
            return tab;
        } else if (simpleName.equalsIgnoreCase("short")) {
            Byte[] tab = new Byte[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                tab[i] = Byte.valueOf(parametresDeMethode[i]);
            }
            return tab;

        } else if (simpleName.equalsIgnoreCase("long")) {
            Long[] tab = new Long[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                tab[i] = Long.valueOf(parametresDeMethode[i]);
            }
            return tab;

        } else if (simpleName.equalsIgnoreCase("double")) {
            Double[] tab = new Double[parametresDeMethode.length];
            for (int i = 0; i < parametresDeMethode.length; i++) {
                tab[i] = Double.valueOf(parametresDeMethode[i]);
            }
            return tab;
        }
        return null;
    }
}
